#include <cstdio>

#include "ImageWindow.h"
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glut.h"
#include "opencv/cv.h"
#include "opencv/highgui.h"

ImageWindow::ImageWindow(OpenGLImage* start, OpenGLImage* end,
		int dynamicFrames, int staticFrames) {
	GLuint *fadeTexIDs = new GLuint[staticFrames];

	this->start = start;
	this->end = end;
	this->width = start->getWidth();
	this->height = start->getHeight();

	getFadeTexIDs(fadeTexIDs, staticFrames);

	this->texQuad = new TextureQuad(start->getTexID(), end->getTexID(),
			fadeTexIDs, dynamicFrames, staticFrames);
}

void ImageWindow::getFadeTexIDs(GLuint* fadeTexIDs, float staticFrames) {
	IplImage* startImg, *endImg, *dstImg;
	double alpha;
	CvSize size;
	int texWidth, texHeight;

	size.height = height;
	size.width = width;
	texWidth = 1 << (int) (ceil(log2(width)));
	texHeight = 1 << (int) (ceil(log2(height)));

	startImg = cvCreateImageHeader(size, IPL_DEPTH_8U, 3);
	endImg = cvCreateImageHeader(size, IPL_DEPTH_8U, 3);
	dstImg = cvCreateImage(size, IPL_DEPTH_8U, 3);

	startImg->imageData = (char*) start->getImageData();
	startImg->imageDataOrigin = startImg->imageData;

	endImg->imageData = (char*) end->getImageData();
	endImg->imageDataOrigin = endImg->imageData;

	for (int i = 0; i < staticFrames; i++) {
		alpha = i / staticFrames;
		cvAddWeighted(startImg, 1 - alpha, endImg, alpha, 0., dstImg);

		glGenTextures(1, &fadeTexIDs[i]);
		glBindTexture(GL_TEXTURE_2D, fadeTexIDs[i]);
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth, texHeight, 0, GL_BGR,
				GL_UNSIGNED_BYTE, dstImg->imageData);
	}
}

void ImageWindow::init() {
	glClearColor(.5, .5, .5, 1.);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(-1., 1., -1., 1.);
}

void ImageWindow::draw() {
	glClear(GL_COLOR_BUFFER_BIT);

	glViewport(0, height, width, height);
	start->draw();

	glViewport(width, height, width, height);
	end->draw();

	glViewport(width >> 1, 0, width, height);
	texQuad->draw();
}

void ImageWindow::mouseFunc(int button, int state, int x, int y) {
	OpenGLImage* image = getImage(x, y);
	if (image) {
		image->mouseFunc(button, state, x, y);
		if (state == GLUT_UP)
			texQuad->update(image);
	}
}

void ImageWindow::motionFunc(int x, int y) {
	OpenGLImage* image = getImage(x, y);
	if (image)
		image->motionFunc(x, y);
}

void ImageWindow::incrFrame() {
	texQuad->incrFrame();
}

OpenGLImage* ImageWindow::getImage(int x, int y) {
	if (x >= 0 && x <= width && y >= height && y <= height << 1)
		return start;
	else if (x >= width && x <= width << 1 && y >= height && y <= height << 1)
		return end;
	return 0;
}
